﻿/**************************************************************************
* @ file    : imi_time.h
* @ author  : yang yang
* @ version : 0.9
* @ date    : 2017.05.15
* @ brief   : 常用时间函数
* @Copyright (c) 2016  chuangmi inc.
***************************************************************************/
 
#ifndef __IMI_TIME_H__
#define __IMI_TIME_H__

/* std c header files */
#include <time.h>
/* user header files */
#include "imi_config.h"
#include "win32.h"

// 时间戳定义, 需要注意的是该时间戳定义实际上是struct timeval
// 因此不能直接相减来获取时间差值，而需要用imi_time_diff
#ifdef __aarch64__
typedef __int128    imi_time_t;
#else
typedef long long   imi_time_t;
#endif

// 时间跨度定义: 单位为micro second (10^-6 sec)
typedef long long imi_timespan_t;

#define TIMESPAN_MILLISECOND   1000LL
#define TIMESPAN_SECOND        1000000LL
#define TIMESPAN_MINUTE        60000000LL
#define TIMESPAN_HOUR          3600000000LL
#define TIMESPAN_DAY           86400000000LL
#define TIMESPAN_WEEK          604800000000LL

#define imi_timespan_add_millisecond(ts, s) (ts + s * TIMESPAN_MILLISECOND)
#define imi_timespan_add_second(ts, s)      (ts + s * TIMESPAN_SECOND)
#define imi_timespan_add_minute(ts, s)      (ts + s * TIMESPAN_MINUTE)
#define imi_timespan_add_hour(ts, s)        (ts + s * TIMESPAN_HOUR)
#define imi_timespan_add_day(ts, s)         (ts + s * TIMESPAN_DAY)
#define imi_timespan_add_week(ts, s)        (ts + s * TIMESPAN_WEEK)

// 时间戳20000101，用于无效时间约定
#define TIMESTAMP_20000101  0x00000000386CD300

#define DEFAULT_TIME_FORMAT     DEFAULT_TIME_FORMAT2
#define DEFAULT_TIME_FORMAT1    "%4d-%2d-%2d %2d:%2d:%2d"
#define DEFAULT_TIME_FORMAT2    "%4d-%02d-%02d %02d:%02d:%02d"
#define DEFAULT_TIME_FORMAT3    "%04d%02d%02d%02d%02d%02d"
#define DEFAULT_TIME_STR_SIZE   32

#ifdef __cplusplus
extern "C" {
#endif

    /* ------------------------- public interfaces: imi_time ------------------------- */

    // 计算2个时间戳的差值 end - start
    // @end   需要比较的第一个时间
    // @start 需要比较的第二个时间
    // @return (end - start)以ms计数的时间间隔
    imi_timespan_t imi_time_diff(imi_time_t end, imi_time_t start);

    // 比较2个时间
    // @first  需要比较的第一个时间
    // @second 需要比较的第二个时间
    // @return 当first小于，等于，大于second时返回-1, 0, 1 
    int imi_time_compare(imi_time_t first, imi_time_t second);

    // 在指定时间戳上增加一定的时间，
    // @tm:    需要计算的timebase
    // @ts:    需要增加的timespan变量，如果需要减的话提供负数即可
    // @return 计算出来的时间
    imi_time_t imi_time_add(imi_time_t tm, imi_timespan_t ts);

    // 读取时间戳中的年月日时分秒信息, 取本地时间
    // @tm:       输入的时间戳
    // @timezone: 指定的时区
    // @year:     输出的year信息
    // @month:    输出的month信息
    // @day:      输出的day信息
    // @hour:     输出hour信息
    // @min:      输出的分钟信息
    // @sec:      输出的秒信息
    void imi_time_parse_local(imi_time_t tm, int timezone, int* year, int* month, int* day, int* hour, int* min, int* sec);

    // 读取时间戳中的年月日时分秒信息, 取UTC时间
    // @tm:     输入的时间戳
    // @year:   输出的year信息
    // @month:  输出的month信息
    // @day:    输出的day信息
    // @hour:   输出hour信息
    // @min:    输出的分钟信息
    // @sec:    输出的秒信息
    void imi_time_parse_utc(imi_time_t tm, int* year, int* month, int* day, int* hour, int* min, int* sec);

    // 读取指定时间的day of week
    // @tm      输入的时间
    // @return  输出的day of week (0-6), 0代表周日
    int imi_time_day_of_week(imi_time_t tm);

    // 读取时间戳的微妙值
    int imi_time_parse_millisecond(imi_time_t tm);

    // 将年月日时分秒信息设置到指定时间结构体里
    // @year:   设置的year信息
    // @month:  设置的month信息
    // @day:    设置的day信息
    // @hour:   设置hour信息
    // @min:    设置的分钟信息
    // @sec:    设置的秒信息
    imi_time_t imi_time_create(int year, int month, int day, int hour, int min, int sec, int ms);

    // 获取当前时间戳
    imi_time_t imi_time_now();

    // 获取now + ts之后的时间戳
    imi_time_t imi_time_future(imi_timespan_t ts);

    // 将imi_time_t转为struct timeval
    void imi_time2timeval(imi_time_t tm, struct timeval *tv);

    // 将struct timeval转为imi_time_t
    imi_time_t timeval2imi_time(struct timeval *tv);

    // 将imi_time_t转为time_t
    time_t imi_time2time_t(imi_time_t tm);

    // 将time_t转为imi_time_t
    imi_time_t time_t2imi_time(time_t time);

    // 格式化时间输出. Format格式请参照strftime函数
    // @注意： 该函数使用了localtime, 不要在多线程里频繁调用
    size_t imi_strftime_local(imi_time_t time, char *strDest, size_t maxsize, const char *format);

    // 格式化时间输出. Format格式请参照strftime函数
    size_t imi_strftime_utc(imi_time_t time, char *strDest, size_t maxsize, const char *format);

    // 读取当前时区timezone
    // @注意： 该函数使用了localtime, 不要在多线程里频繁调用, 建议调用一次后保存下来
    // @return 当前时区的小时偏移[-12. 12]
    int imi_local_timezone();

    // 将imi_time_t转成自1970.01.01以来流逝的micro second数
    long long imi_time_elapse(imi_time_t tm);

    /* ------------------------- public interfaces: tv_time ------------------------- */

    // timeval的相关操作，参数同imi_time相关函数
    imi_timespan_t tv_time_diff(struct timeval *end, struct timeval *start);
    int tv_time_compare(struct timeval *first, struct timeval *second);
    void tv_time_add(struct timeval *tv, imi_timespan_t ts);
    void tv_time_future(struct timeval *tv, imi_timespan_t ts);
    void tv_time_parse_local(struct timeval *tv, int timezone, int* year, int* month, int* day, int* hour, int* min, int* sec);
    void tv_time_parse_utc(struct timeval *tv, int* year, int* month, int* day, int* hour, int* min, int* sec);
    int tv_time_day_of_week(struct timeval *tv);
    void tv_time_set(struct timeval *tv, int year, int month, int day, int hour, int min, int sec, int ms);


    // 将imi_time_t转换为struct timespec
    void imi_time2timespec(imi_time_t tm, struct timespec *timespec);

    // 获取now + ts之后的时间戳
    void timespec_future(struct timespec *timespec, imi_timespan_t ts);

    /* ------------------------ public interfaces: time_utils ------------------------ */

    // time_t to struct tm
    API_PUBLIC(struct tm) time_to_tm(time_t time);

    // struct tm to string(not thread safe)
    API_PUBLIC(const char*) tm_to_time_string(struct tm tmstruct);
    API_PUBLIC(const char*) tm_to_time_string_ex(struct tm tmstruct, const char *time_format);

    // struct tm to time_t
    API_PUBLIC(time_t) tm_to_time_t(struct tm s_tm);

    // get current time, format: mmddhhmmss
    API_PUBLIC(const char*) get_local_time();

    // return timestamp of millisecond
    API_PUBLIC(long long) time_t_milli();
    // return timestamp of microsecond
    API_PUBLIC(long long) time_t_micro();

    /* ----- UTC <==> CUT(Coordinated Universal Time) <==> LOC ----- */

    // utc time to local time
    API_PUBLIC(time_t) utc_to_local(time_t time);
    // local time ot utc time
    API_PUBLIC(time_t) local_to_utc(time_t time);

    // demo to print current time
    API_PRIVATE(void) print_current_time();

#ifdef __cplusplus
}
#endif

#endif // __IMI_TIME_H__